﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using NetBay.Core.BusinessEntities;
using NetBay.Core.BusinessEntities.AdvancedSearchCriteria;
using Rio.Applications.Web.Services;


namespace Rio.Framework.Pages.CriteriaControls
{

    /// <summary>
    /// Criteria control container
    /// </summary>
    public partial class AdvancedSearchControl : ControlBase, INotifyPropertyChanged
    {
        #region Attributs

        private Dictionary<Guid, CriteriaControlBase> _internalControl;
        private Index _index;
        private long _OrganizationIdentifier;
        private long _folderTypeIdentifier;
        private DisplayOperatorPossible _operator;
        private SqlEqualityOperator _previouslyOperator;

        #endregion

        #region Events

        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Called when [notify property changed].
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        public void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion

        #region Properties

        /// <summary>
        /// Get or Set current index
        /// </summary>
        public Index CurrentIndex
        {
            get { return _index; }
            set 
            {
                _index = value;
                Initialize();
            }
        }

        /// <summary>
        /// Selected Operator
        /// </summary>
        public DisplayOperatorPossible SelectedOperator
        {
            get { return _operator; }
            set
            {
                _operator = value;
                OnPropertyChanged("SelectedOperator");
                ChangeFilterVisibility(_operator);
            }
        }

        /// <summary>
        /// Folder type identifier
        /// </summary>
        public long FolderTypeIdentifier
        {
            get { return _folderTypeIdentifier; }
            set
            {
                _folderTypeIdentifier = value;
            }
        }

        #endregion

        #region Dependency properties

        /// <summary>
        /// 
        /// </summary>
        public bool AddControlEnabled
        {
            get 
            {
                return AddButton.IsEnabled;
            }
            set 
            {
                AddButton.IsEnabled = value;
            }
        }


        #endregion

        #region Constructors

        public AdvancedSearchControl()
        {
            InitializeComponent();
            InitLabel();
            _internalControl = new Dictionary<Guid, CriteriaControlBase>();
            this.Name = Guid.NewGuid().ToString();
            AddControlEnabled = false;
        }

        public AdvancedSearchControl(Index index, long organizationIdentifier, long folderTypeIdentifier)
            :this()
        {
            this._index = index;
            this._folderTypeIdentifier = folderTypeIdentifier;
            this._OrganizationIdentifier = organizationIdentifier;
            Initialize();
        }

        #endregion

        #region Private functions

        /// <summary>
        /// Changes visibility of add control button
        /// </summary>
        /// <param name="op"></param>
        private void ChangeFilterVisibility(DisplayOperatorPossible op)
        {
            if (op != null)
            {
                if (IsTextIndex())
                {
                    AddControlEnabled = true;
                }
                else if (IsDateIndex() || IsNumericalIndex())
                {
                    
                    if (op.Value == SqlEqualityOperator.Superior 
                        || op.Value == SqlEqualityOperator.Inferior 
                        || op.Value == SqlEqualityOperator.SuperiorOrEqual 
                        || op.Value == SqlEqualityOperator.InferiorOrEqual)
                    {
                        //Keep only one control and disabled add button
                        AddControlEnabled = false;
                        BuildControlForNumericalOperator();
                    }
                    else if (op.Value == SqlEqualityOperator.Between)
                    {
                        //Keep only two controls and disabled add button
                        AddControlEnabled = false;
                        BuildControlForBetweenOperator();
                    }
                    else
                    {
                        if (_previouslyOperator == SqlEqualityOperator.Between)
                        {
                            Clear();
                            AddControl(false);
                        }
                        AddControlEnabled = true;
                    }
                }
                _previouslyOperator = op.Value;
            }
        }

        /// <summary>
        /// Adds control 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonAdd_Click(object sender, RoutedEventArgs e)
        {
            AddControl(true);
        }

        /// <summary>
        /// Adds a control
        /// </summary>
        private void AddControl(bool isRemoveActive)
        {
            CriteriaControlBase control = CriteriaFactory.CreateControl(_index, _folderTypeIdentifier, false, true);
            control.DisableMandatoryLabel();
            control.DisableIndexLabel();
            control.DisableFilter();
            if (isRemoveActive)
                control.ActiveRemove();
            control.RemoveControlClick += OnRemovedControl;
            control.AcceptSpecialCharsForRegularExpression = true;
            StackControl.Children.Add(control);
            control.Focus();
            this._internalControl.Add(control.UniqueId, control);
        }

        /// <summary>
        /// Removes a control
        /// </summary>
        /// <param name="control"></param>
        private void RemovedControl(CriteriaControlBase control)
        {
            if (this._internalControl.Count > 1)
            {
                control.RemoveControlClick -= OnRemovedControl;
                StackControl.Children.Remove(control);
                this._internalControl.Remove(control.UniqueId);
            }
        }

        /// <summary>
        /// Build two controls
        /// </summary>
        private void BuildControlForBetweenOperator()
        {
            if (this._internalControl.Count == 1)
            {
                AddControl(false);
            }
            else if (this._internalControl.Count > 1)
            {
                //We must keep only two controls
                int counterLoop = 0;
                List<CriteriaControlBase> toRemove = new List<CriteriaControlBase>();
                foreach (KeyValuePair<Guid, CriteriaControlBase> item in this._internalControl)
	            {
		            if (counterLoop > 1)
                    {
                        toRemove.Add(item.Value);
                    }
                    counterLoop++;
	            }
                //Remove controls
                foreach (CriteriaControlBase item in toRemove)
                {
                    RemovedControl(item);
                }
            }
        }

        /// <summary>
        /// Build two controls
        /// </summary>
        private void BuildControlForNumericalOperator()
        {
            if (this._internalControl.Count > 1)
            {
                //We must keep only two controls
                int counterLoop = 0;
                List<CriteriaControlBase> toRemove = new List<CriteriaControlBase>();
                foreach (KeyValuePair<Guid, CriteriaControlBase> item in this._internalControl)
                {
                    if (counterLoop > 0)
                    {
                        toRemove.Add(item.Value);
                    }
                    counterLoop++;
                }
                //Remove controls
                foreach (CriteriaControlBase item in toRemove)
                {
                    RemovedControl(item);
                }
            }
        }

        /// <summary>
        /// Remove control event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnRemovedControl(object sender, EventArgs e)
        {
            RemovedControl(sender as CriteriaControlBase);
        }

        /// <summary>
        /// Indicates whether the index is numeric type
        /// </summary>
        /// <returns></returns>
        private bool IsNumericalIndex()
        {
            if (this._index != null)
            {
                switch (this._index.Type)
                {
                    case (int)IndexDomainServiceEnums.IndexType.Double:
                    case (int)IndexDomainServiceEnums.IndexType.Integer:
                        return true;
                    default :
                        return false;
                }
            }
            return false;
        }

        /// <summary>
        /// Indicates whether the index is date type
        /// </summary>
        /// <returns></returns>
        private bool IsDateIndex()
        {
            if (this._index != null)
            {
                switch (this._index.Type)
                {
                    case (int)IndexDomainServiceEnums.IndexType.Date:
                        return true;
                    default:
                        return false;
                }
            }
            return false;
        }

        /// <summary>
        /// Indicates whether the index is text type
        /// </summary>
        /// <returns></returns>
        private bool IsTextIndex()
        {
            if (this._index != null)
            {
                switch (this._index.Type)
                {
                    case (int)IndexDomainServiceEnums.IndexType.Boolean:
                    case (int)IndexDomainServiceEnums.IndexType.DocumentType:
                    case (int)IndexDomainServiceEnums.IndexType.Groups:
                    case (int)IndexDomainServiceEnums.IndexType.IntegerString:
                    case (int)IndexDomainServiceEnums.IndexType.ListeOfRecipient:
                    case (int)IndexDomainServiceEnums.IndexType.ListOfSenders:
                    case (int)IndexDomainServiceEnums.IndexType.ListOfValues:
                    case (int)IndexDomainServiceEnums.IndexType.Object:
                    case (int)IndexDomainServiceEnums.IndexType.String:
                    case (int)IndexDomainServiceEnums.IndexType.TypeChrono:
                    case (int)IndexDomainServiceEnums.IndexType.TypeFlow:
                    case (int)IndexDomainServiceEnums.IndexType.Users:
                        return true;
                    default:
                        return false;
                }
            }
            return false;
        }

        #endregion

        #region Public Functions

        /// <summary>
        /// Init all labels
        /// </summary>
        public override void InitLabel()
        {
        }

        /// <summary>
        /// Returns inputed Criterias
        /// </summary>
        /// <returns></returns>
        public AdvancedSearchCriteriaItem GetCriterias()
        {
            AdvancedSearchCriteriaItem criteria = new AdvancedSearchCriteriaItem();
            if (ComboComparator.SelectedOperator != null)
            {
                criteria.Operator = ComboComparator.SelectedOperator.Value;
                criteria.IndexIdentifier = this.CurrentIndex.Indentifier;

                //list of values
                List<string> values = new List<string>();
                foreach (KeyValuePair<Guid, CriteriaControlBase> item in _internalControl)
                {
                    if (!string.IsNullOrEmpty(item.Value.InputValue))
                        values.Add(item.Value.InputValue);
                }
                criteria.CriteriaValue = values;
            }
            return criteria;
        }

        /// <summary>
        /// Clear control
        /// </summary>
        public void Clear()
        {
            foreach (KeyValuePair<Guid, CriteriaControlBase> item in _internalControl)
            {
                item.Value.RemoveControlClick -= OnRemovedControl;
            }
            StackControl.Children.Clear();
            _internalControl.Clear();
        }

        /// <summary>
        /// Clear all criteria
        /// </summary>
        public void ClearCriterias()
        {
            foreach (KeyValuePair<Guid, CriteriaControlBase> item in _internalControl)
            {
                item.Value.Clear();
            }
        }

        /// <summary>
        /// Adds main control, this cannot be removed
        /// </summary>
        public void Initialize()
        {
            //Clear control
            Clear();

            ComboComparator.Index = this.CurrentIndex;
            LabelControl.Text = this._index.IndexLabel;

            //Add first control
            AddControl(false);
        }

        #endregion
    }
}
